<template>
    <!-- 上传 使用oos上传 支持 单个、多个、图片、文件等 -->
    <el-upload
        v-bind="$attrs"
        v-on="$listeners"
        ref='upload'
        action="/maintain/oss/uploadFile"
        class="yi-upload"
        :http-request="httpRequest"
        :show-file-list="false"
        :before-upload="beforeUpload"
        :limit="limit"
        :on-progress="onProgress"
        :disabled="disabled || limit <= fileList.length"
    >
        <template v-if="fileList.length > 0">
            <div v-for="(item, index) in fileList" :key="index" class="file-box">
                <!-- 处理不同类型的文件 使用component is -->
                <component :ref="`component-${index}`" :is="`Y${item.type}`" :data="item" :fileList="fileList"></component>
                <!-- 处理不同类型的文件 -->
                <span class="el-upload-list__item-actions" @click.stop="handleStop()">
                    <span v-if="item.type === 'image'" class="item-preview" @click.stop="handleFilePreview(item, index)">
                        <i class="el-icon-zoom-in"></i>
                    </span>
                    <span class="item-delete" v-if="!disabled && deleteFileMethod(item)" @click.stop="handleFileRemove(item, index)">
                        <i class="el-icon-delete"></i>
                    </span>
                </span>
            </div>
        </template>
        <div class="avatar-uploader-icon" v-if="limit > fileList.length && !disabled">
            <i v-show="!progreessFlag" class="el-icon-plus"></i>
            <el-progress v-if="progreessFlag" type="circle" :percentage="percentage" :show-text="true"></el-progress>
        </div>
    </el-upload>
</template>

<script>
import { upLoading } from "@/api/system/user.js";
import { Yimage, Ytext, Yzip, Yvideo, Yaudio } from "./components/index";
import { errorInfo, success, warning } from "@/utils/errorInfo";
export default {
    name: "YiUpload",
    inheritAttrs: false,
    components: {
        Yimage,
        Ytext,
        Yzip,
        Yvideo,
        Yaudio
    },
    props: {
        checkType: {
            type: [String, Array],
            default: "image"
        },
        isSize: {
            type: Boolean,
            default: false
        },
        fileSize: { // 文件大小 单位 MB
            type: Number,
            default: 50
        },
        limit: { // 最多上传多少文件
            type: Number,
            default: 1
        },
        storagePath: {
            type: String,
            required: true
        },
        disabled: {
            type: Boolean,
            default: false
        },
        deleteFileMethod: {
            type: Function,
            default: () => {
                return true;
            }
        }
    },
    data() {
        return {
            fileType: [
                {
                    name: "图片",
                    type: "image",
                    suffix: ["jpg", "png", "gif", "jpeg", "psd"]
                },
                {
                    name: "音频",
                    type: "audio",
                    suffix: ["map3", "mpeg", "aiff", "flac", "acc", "ape", "mid", "wav"]
                },
                {
                    name: "视频",
                    type: "video",
                    suffix: ["avi", "wmv", "mp4", "mpg", "mov", "rm", "ram", "swf", "flv"]
                },
                {
                    name: "压缩文件",
                    type: "zip",
                    suffix: ["zip", "7z", "rar"]
                },
                {
                    name: "文件",
                    type: "text",
                    suffix: ["txt", "docx", "xlsx", "pdf", "ppt", "md"]
                },
                {
                    name: "PDF",
                    type: "pdf",
                    suffix: ['pdf']
                }
            ],
            fileList: [], // 上传的文件列表
            fileListOriginal: [], // 针对于编辑时处理图片
            progreessFlag: false, // 进度条展示
            percentage: 0
        }
    },
    methods: {
        isCheckType(type) { // 校验文件后缀类型是否匹配
            let isType = false;
            let fileType = [];
            if (Object.prototype.toString.call(this.checkType) === '[object String]') { // String
                fileType = this.fileType.filter(item => item.type === this.checkType);
            } else if (Object.prototype.toString.call(this.checkType) === '[object Array]') { // Array
                fileType = this.fileType.filter(item => this.checkType.includes(item.type));
            } else {
                this.$Message.error('上传组件配置文件类型错误.');
            }
            let suffix = [];
            fileType.forEach(item => { suffix = [...suffix, ...item.suffix] });
            isType = suffix.some(item => type.includes(item));
            // 错误提示
            if (!isType) {
                let message = "";
                fileType.forEach(item => {
                    message += `${item.name}: ${item.suffix.toString()}; <br />`
                })
                warning(`文件支持:<br />${message}`, '上传文件类型错误');
            }
            return isType;
        },
        isFileSize(size) { // 校验文件大小（后期可以在这里修改为独立大小配置）
            let isSize = size <= this.fileSize * 1024 * 1024;
            if (!isSize) {
                warning(`上传文件大小支持最大 ${this.fileSize}MB`, '上传文件大小错误');
            }
            return isSize;
        },
        beforeUpload(file) { // 上传前拦截
            let isUpload = false;
            const { name, size } = file; // 文件类型
            // 判断是否配置 文件path
            if (this.storagePath) {
                // 1. 判断上传的文件类型
                let isType = this.isCheckType(name);
                if (isType) { // 2. 判断文件大小最大15MB
                    if (this.isSize) {
                        let isSize = this.isFileSize(size);
                        if (isSize) isUpload = true;
                    } else isUpload = true;
                }
            } else {
                warning('为配置 storagePath 文件上传路径');
            }
            return isUpload;
        },
        httpRequest(data) { // 请求后端接口上传
            const file = data.file;
            let formData = new FormData();
            formData.append("file", file);
            formData.append("storagePath", this.storagePath); //传projectId
            this.progreessFlag = true;
            upLoading(formData, {
                headers: {
                    "Content-Type": "multipart/form-data"
                },
                onUploadProgress: event => {
                    event.percent = (event.loaded / event.total) * 100
                    data.onProgress(event, file);
                }
            }).then((res) => {
                this.progreessFlag = false;
                this.percentage = 0;
                success('上传成功');
                let data = res.data || {};
                const fileUrl = data.fileUrl || "";
                const fileSaveName = data.fileName;
                const fileName = this.handleFileName(data.fileName);
                let fileType = this.fileType.filter(item => {
                    return item.suffix.some(suffix => file.name.includes(suffix));
                });
                // 单文件/多文件处理
                if (this.limit === 1) { // 单文件 默认 1
                    this.fileList = [{ fileUrl, type: fileType[0].type, fileName, fileSaveName }];
                } else {
                    this.fileList.push({ fileUrl, type: fileType[0].type, fileName, fileSaveName });
                }
                this.$emit('uploadSuccess', this.getFileList());
            }).catch((error) => {
                this.$refs.upload.clearFiles();
                this.progreessFlag = false;
                this.percentage = 0;
                errorInfo('上传失败，请稍后重试');
            })
        },
        onProgress(event, file) {
            this.percentage = Math.floor(event.percent);
        },
        handleFileRemove(item, index) { // 文件删除
            this.fileList.splice(index, 1);
            this.$refs.upload.clearFiles();
            this.$emit('uploadSuccess', this.getFileList());
        },
        handleStop() {},// 此函数防止再次触发上传事件，勿删！！！
        handleFileName(fileName) {
            let index = fileName.indexOf('_');
            return fileName.slice(index + 1, fileName.length);
        },
        handleFilePreview(item, index) { // 图片预览
            this.$refs[`component-${index}`][0].handlePreview();
        },
        isFile() { // 校验文件是否有
            let lock = false;
            if (this.fileList && this.fileList.length > 0) lock = true;
            else lock = false;
            return lock;
        },
        getFileList() { // 获取图片列表
            const addFile = this.differenceSet(this.fileList, this.fileListOriginal);
            const deleteFile = this.differenceSet(this.fileListOriginal, this.fileList);
            const files = [...this.fileListOriginal, ...addFile];
            return files.map(item => {
                return {
                    ...item,
                    delFlag: deleteFile.some(d_item => d_item.id === item.id) ? 1 : 0
                }
            })
        },
        setFileList(data) { // 回显图片列表
            this.fileList.length = 0;
            this.fileListOriginal.length = 0;
            let fileList = [];
            data.forEach((item) => {
                let suffixIndex = item.fileSaveName.lastIndexOf('.');
                let suffixName = item.fileSaveName.slice(suffixIndex + 1, item.length);
                let fileType = this.fileType.filter(fileTypeItem => {
                    return fileTypeItem.suffix.some(suffix => suffix === suffixName.toLowerCase());
                })
                const fileName = this.handleFileName(item.fileSaveName);
                fileList.push({
                    id: item.id,
                    fileUrl: item.fileUrl,
                    fileSaveName: item.fileSaveName,
                    type: fileType[0].type,
                    fileName,
                    delFlag: item.delFlag || 0,
                    params: {
                        ...item
                    }
                });
            })
            this.fileList = fileList.filter(item => item.delFlag === 0);
            this.fileListOriginal = [...fileList];
        },
        differenceSet(A, B) {
            const difference = A.concat(B).filter((val) => {
                return A.find((A_item) => {
                    return A_item.id === val.id;
                }) && !B.find((B_item) => {
                    return B_item.id === val.id;
                })
            })
            return difference;
        }
    }
}
</script>

<style>
    .yi-upload {
        display: inline-block;
    }
    .yi-upload .el-upload {
        display: flex;
        flex-wrap: wrap;
        flex-direction: row;
    }
    .yi-upload .el-upload .avatar-uploader-icon {
        border: 1px dashed #d9d9d9;
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
        margin-bottom: 6px;
    }
    .yi-upload .file-box {
        border: 1px dashed #d9d9d9;
        border-radius: 6px;
        position: relative;
        overflow: hidden;
        display: inline-block;
        margin-right: 6px;
        margin-bottom: 6px;
    }
    /* .yi-upload .file-box + .file-box {
        margin-left: 10px;
    } */
    .yi-upload .el-upload .avatar-uploader-icon:hover {
        border-color: #409eff;
    }
    .yi-upload .el-upload:hover .avatar-uploader-icon {
        color: #409eff;
    }
    .yi-upload .avatar-uploader-icon {
        font-size: 28px;
        color: #8c939d;
        width: 120px;
        height: 115px;
        line-height: 115px;
        text-align: center;
    }
    .yi-upload .avatar {
        width: 120px;
        height: 115px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    .yi-upload .avatar .el-image {
        width: 100%;
        height: 100%;
    }
    .yi-upload .el-icon-document,
    .yi-upload .el-icon-collection {
        font-size: 40px;
        color: #606266 !important;
    }
    .yi-upload .fileName {
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        padding: 0 10px;
        color: #606266 !important;
    }
    .yi-upload .el-upload-list__item-actions:hover {
        opacity: 1;
    }
    .yi-upload .el-upload-list__item-actions {
        position: absolute;
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        cursor: default;
        text-align: center;
        color: #fff;
        opacity: 0;
        font-size: 20px;
        background-color: rgba(0, 0, 0, 0.5);
        transition: opacity 0.3s;
        line-height: 110px;
    }
    .yi-upload .el-upload-list__item-actions span {
        display: none;
        cursor: pointer;
    }
    .yi-upload .el-upload-list__item-actions:hover span {
        display: inline-block;
    }
    .yi-upload .item-delete {
        transition: all .25s;
    }
    .yi-upload .item-preview {
        transition: all .25s;
        margin-right: 10px;
    }
    .yi-upload .item-delete:hover {
        color: #409eff;
    }
    .yi-upload .item-preview:hover {
        color: #409eff;
    }
    .yi-upload .avatar-uploader-icon .el-progress {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 110px;
        height: 110px;
    }
    .yi-upload .avatar-uploader-icon .el-progress .el-progress-circle{
        width: 110px !important;
        height: 110px !important;
    }
</style>
